﻿// License: The MIT License (MIT) Copyright (c) 2011..2012 Barend Gehrels

// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;

namespace GrooveSharp
{
    // firstMediaElement: the real WPF player. Called "first" because we might add a "second" later.


    public partial class MainPlayer : UserControl, IPlayer
    {
        private DispatcherTimer m_Timer;

        // Alas keeping state is necessary
        // http://stackoverflow.com/questions/4338951/how-do-i-determine-if-mediaelement-is-playing
        private bool m_IsPlaying = false;
        private bool m_IsPaused = false;
        private bool m_PausedBecauseOfHibernate = false;

        private bool m_FadingOut = false;

        // Declare 3 events using the cookbook therefore
        public static readonly RoutedEvent MusicStartEvent =
                  EventManager.RegisterRoutedEvent("MusicStart", RoutingStrategy.Bubble,
                    typeof(RoutedEventHandler), typeof(MainPlayer));
        public static readonly RoutedEvent MusicFadeEnd =
                  EventManager.RegisterRoutedEvent("MusicFade", RoutingStrategy.Bubble,
                    typeof(RoutedEventHandler), typeof(MainPlayer));
        public static readonly RoutedEvent MusicEndEvent =
                  EventManager.RegisterRoutedEvent("MusicEnd", RoutingStrategy.Bubble,
                    typeof(RoutedEventHandler), typeof(MainPlayer));

        public event RoutedEventHandler MusicStart
        {
            add { AddHandler(MusicStartEvent, value); }
            remove { RemoveHandler(MusicStartEvent, value); }
        }
        public event RoutedEventHandler MusicFade
        {
            add { AddHandler(MusicFadeEnd, value); }
            remove { RemoveHandler(MusicFadeEnd, value); }
        }
        public event RoutedEventHandler MusicEnd
        {
            add { AddHandler(MusicEndEvent, value); }
            remove { RemoveHandler(MusicEndEvent, value); }
        }


        public MainPlayer()
        {
            InitializeComponent();

            m_Timer = new DispatcherTimer();
            m_Timer.Tick += new EventHandler(timer_Tick);
            m_Timer.Interval = TimeSpan.FromSeconds(0.1);

            firstMediaElement.LoadedBehavior = MediaState.Manual;
            firstMediaElement.Volume = 0.5;
            //firstMediaElement.Volume = 0.1;
#if DEBUG
            // Uncomment if you want to play fast and soft
            //firstMediaElement.Volume = 0.02;
            //firstMediaElement.SpeedRatio = 100.0;
#endif
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            try
            {
                if (mediaProgressBar.Maximum > 0 && firstMediaElement.NaturalDuration.HasTimeSpan)
                {
                    mediaProgressBar.Value = firstMediaElement.Position.TotalMilliseconds;
                    if (!m_FadingOut)
                    {
                        double MsLeft = firstMediaElement.NaturalDuration.TimeSpan.TotalMilliseconds - firstMediaElement.Position.TotalMilliseconds;
                        if (MsLeft > 0 && MsLeft < 1200)
                        {
                            m_FadingOut = true;
                            RaiseEvent(new RoutedEventArgs(MusicFadeEnd));
                        }
                    }

                }
            }
            catch { }
        }


        private void mainMediaElement_MediaOpened(object sender, RoutedEventArgs e)
        {
            m_IsPaused = false;
            m_FadingOut = false;
            if (firstMediaElement.NaturalDuration.HasTimeSpan)
            {
                mediaProgressBar.Value = 0;
                mediaProgressBar.Maximum = firstMediaElement.NaturalDuration.TimeSpan.TotalMilliseconds;
            }
            m_Timer.Start();

            RaiseEvent(new RoutedEventArgs(MusicStartEvent));
        }

        private void mainMediaElement_MediaEnded(object sender, RoutedEventArgs e)
        {
            App.Log.InfoFormat("End playing {0}", firstMediaElement.Source);

            m_IsPlaying = false;
            m_IsPaused = false;

            m_Timer.Stop();
            RaiseEvent(new RoutedEventArgs(MusicEndEvent));
        }

        public void Play(TrackInfo info)
        {
            // Set m_IsPlaying immediately to avoid async events such as "NextIfNotStarted" to wait until media player has been opened
            m_IsPlaying = true;
            firstMediaElement.Source = new Uri(info.FileName, UriKind.RelativeOrAbsolute);
            firstMediaElement.Play();

            App.Log.InfoFormat("Start playing {0}", firstMediaElement.Source);
        }

        public void Stop()
        {
            try
            {
                if (m_IsPlaying)
                {
                    App.Log.InfoFormat("Stop playing {0}", firstMediaElement.Source);
                }
                firstMediaElement.Stop();
                mediaProgressBar.Value = 0;
                mediaProgressBar.Maximum = 1;
            }
            catch
            {
            }
        }

        public bool TogglePause()
        {
            if (m_IsPaused)
            {
                firstMediaElement.Play();
                App.Log.InfoFormat("Resume playing {0}", firstMediaElement.Source);
            }
            else
            {
                firstMediaElement.Pause();
                App.Log.InfoFormat("Pause playing {0}", firstMediaElement.Source);
            }
            m_IsPaused = ! m_IsPaused;
            return m_IsPaused;
        }

        public bool Playing()
        {
            return m_IsPlaying;
        }

        public bool IsPaused()
        {
            return ! m_IsPlaying || m_IsPaused;
        }


        public void SetPowerMode(Microsoft.Win32.PowerModes mode)
        {
            App.Log.InfoFormat("Power mode changed: {0}", mode);
            switch (mode)
            {
                case Microsoft.Win32.PowerModes.Resume:
                    if (m_PausedBecauseOfHibernate && m_IsPaused)
                    {
                        TogglePause();
                        m_PausedBecauseOfHibernate = false;
                    }
                    break;
                case Microsoft.Win32.PowerModes.Suspend:
                    if (m_IsPlaying)
                    {
                        m_PausedBecauseOfHibernate = true;
                        TogglePause();
                    }
                    break;
            }
        }
    }
}
